package br.com.pentagrama.service.ui.screen;

import java.awt.Container;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.border.Border;

import br.com.pentagrama.service.DataStore;
import br.com.pentagrama.service.ui.component.ControlRow;
import br.com.pentagrama.service.ui.component.Field;
import br.com.pentagrama.service.ui.component.IPRangeField;
import br.com.pentagrama.service.ui.component.PortRangeField;
import br.com.pentagrama.service.ui.component.RangeRow;
import br.com.pentagrama.service.ui.event.IPRangeChangedEvent;
import br.com.pentagrama.service.ui.event.PortRangeChangedEvent;

public class RegistrationScreen {
	private DataStore portRangeDataStore;
	private DataStore ipRangeDataStore;
	
	private static final int ROW_HEIGHT = 25;

	private JPanel ipRangePanel;
	private JPanel portRangePanel;

	private JScrollPane ipRangeScrollPane;
	private JScrollPane portRangeScrollPane;
	
	private ControlRow ipRangeControlRow;
	private ControlRow portRangeControlRow;

	private JButton saveButton;

	private String startPort;
	private String endPort;

	private String startIp;
	private String endIp;

	private List<RangeRow> ipRangeRows;
	private List<RangeRow> portRangeRows;
	
	private Map<String, String> portRanges;
	private Map<String, String> ipRanges;
	
	public RegistrationScreen(DataStore ipRangeDataStore, DataStore portRangeDataStore) {
		super();
		
		this.portRanges = new HashMap<String, String>();
		this.ipRanges = new HashMap<String, String>();
		
		this.portRangeDataStore = portRangeDataStore;
		this.ipRangeDataStore = ipRangeDataStore;
		
		ipRangeRows = new ArrayList<RangeRow>();
		portRangeRows = new ArrayList<RangeRow>();

		ipRangePanel = new JPanel();	
		ipRangePanel.setLayout(new BoxLayout(ipRangePanel, BoxLayout.Y_AXIS));
		Border ipRangeHeader = BorderFactory
				.createTitledBorder("Faixas de IPs");
		ipRangePanel.setBorder(ipRangeHeader);

		portRangePanel = new JPanel();
		portRangePanel
				.setLayout(new BoxLayout(portRangePanel, BoxLayout.Y_AXIS));
		Border portRangeHeader = BorderFactory
				.createTitledBorder("Faixas de portas");
		portRangePanel.setBorder(portRangeHeader);

		ipRangeScrollPane = new JScrollPane(ipRangePanel,
				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

		portRangeScrollPane = new JScrollPane(portRangePanel,
				JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);

		ipRangeControlRow = new ControlRow(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				addIpRangeRow();
			}
		}, null);
		
		portRangeControlRow = new ControlRow(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				addPortRangeRow();
			}
		}, null);
		
		saveButton = new JButton("Salvar");
		saveButton.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
				StringBuilder errorMessage = new StringBuilder();
				validate(errorMessage);
				if (errorMessage.length() == 0) {
					save();
				} else {
					JOptionPane.showMessageDialog(null, errorMessage.toString());
				}
			}		
		});
	}

	public void showIn(Container container) {

		ipRangeControlRow.showIn(ipRangePanel);
		portRangeControlRow.showIn(portRangePanel);

		container.add(ipRangeScrollPane);
		container.add(portRangeScrollPane);
		
		Box saveButtonBox = Box.createHorizontalBox();
		saveButtonBox.add(saveButton);
		saveButtonBox.add(Box.createHorizontalGlue());
		container.add(saveButtonBox);

		addIpRangeRow();
		addPortRangeRow();
	}

	private void addIpRangeRow() {
		Field field = new IPRangeField(350, ROW_HEIGHT,
				new IPRangeChangedEvent() {
					private int rowIndex = ipRangeRows.size();
					public void updateValue(String start, String end) {
						startIp = start;
						endIp = end;
						
						ipRanges.put(String.valueOf(rowIndex), startIp + " - " + endIp);
						
						System.out.println(rowIndex + ") " + startIp + " - " + endIp);
					}
				});

		RangeRow row = new RangeRow(ipRangeRows.size(), 520, ROW_HEIGHT, field);

		addRow(row, ipRangeRows, ipRangePanel);
	}

	private void addPortRangeRow() {
		Field field = new PortRangeField(140, ROW_HEIGHT,
				new PortRangeChangedEvent() {
					private int rowIndex = portRangeRows.size();
					public void updateValue(String start, String end) {
						startPort = start;
						endPort = end;
						
						portRanges.put(String.valueOf(rowIndex), startPort + " - " + endPort);
						
						System.out.println(rowIndex + ") " + startPort + " - " + endPort);
					}
				});

		RangeRow row = new RangeRow(portRangeRows.size(), 300, ROW_HEIGHT,
				field);

		addRow(row, portRangeRows, portRangePanel);
	}

	private void addRow(RangeRow row, Collection<RangeRow> rows,
			Container container) {
		int componentCount = container.getComponentCount();
		if (componentCount > 2) {
			container.remove(componentCount - 1);		
		}
		Box box = Box.createHorizontalBox();
		row.showIn(box);
		rows.add(row);
		box.add(Box.createHorizontalGlue());
		container.add(box);
		container.add(Box.createVerticalGlue());
		//container.revalidate();
	}
	
	private void validate(StringBuilder errorMessage) {
		validateRanges(ipRanges, "As seguintes faixas de IPs não foram devidamente preenchidas: ", "\\d{1,3}(.\\d{1,3}){3}\\s-\\s\\d{1,3}(.\\d{1,3}){3}", errorMessage);
		errorMessage.append("\n");
		validateRanges(portRanges, "As seguintes faixas de portas não foram devidamente preenchidas: ", "\\d+\\s-\\s\\d+", errorMessage);
	}
	
	private void validateRanges(Map<String, String> data, String messageSubject, String rangePattern, StringBuilder errorMessage) {
		StringBuilder invalidPortRanges = new StringBuilder();
		
		for (String key : data.keySet()) {
			String ipRange = data.get(key);
			 
			if (!ipRange.matches(rangePattern)) {
				invalidPortRanges
				.append((Integer.parseInt(key) + 1))
				.append(" ");
			}
		}
				
		if (invalidPortRanges.length() > 0) {
			errorMessage
			.append(messageSubject)
			.append(invalidPortRanges);
		}
	}
	
	private void save() {
		save(ipRanges, ipRangeDataStore);
		save(portRanges, portRangeDataStore);
	}
	
	private void save(Map<String, String> data, DataStore dataStore) {
		for (String key : data.keySet()) {
			dataStore.store(key, data.get(key));
		}
	}
}
